///////////////////////////////////////////////////////////////
//  Copyright Christopher Kormanyos 2002 - 2011.
//  Copyright 2011 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
//
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif

#include <boost/detail/lightweight_test.hpp>
#include <boost/array.hpp>
#include "test.hpp"

#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && \
    !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) &&    \
    !defined(TEST_CPP_BIN_FLOAT)
#define TEST_MPF_50
//#  define TEST_MPF
#define TEST_BACKEND
#define TEST_CPP_DEC_FLOAT
#define TEST_MPFI_50
#define TEST_FLOAT128
#define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50)
#include <nil/crypto3/multiprecision/gmp.hpp>
#endif
#if defined(TEST_MPFR_50)
#include <nil/crypto3/multiprecision/mpfr.hpp>
#endif
#if defined(TEST_MPFI_50)
#include <nil/crypto3/multiprecision/mpfi.hpp>
#endif
#ifdef TEST_BACKEND
#include <nil/crypto3/multiprecision/concepts/mp_number_archetypes.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <nil/crypto3/multiprecision/cpp_dec_float.hpp>
#endif
#ifdef TEST_FLOAT128
#include <nil/crypto3/multiprecision/float128.hpp>
#endif
#ifdef TEST_CPP_BIN_FLOAT
#include <nil/crypto3/multiprecision/cpp_bin_float.hpp>
#endif

#ifdef BOOST_MSVC
#pragma warning(disable : 4127)
#endif

template<class T>
T atan2_def(T y, T x) {
    T t;
    t.backend() = nil::crypto3::multiprecision::default_ops::get_constant_pi<typename T::backend_type>();
    T t2;
    if (x)
        t2 = atan(y / x);
    else
        t2 = y.sign() * t / 2;
    return t2 + (t / 2) * (1 - x.sign()) * T(y.sign() + 0.5).sign();
}

template<class T>
struct is_mpfr_type : public boost::mpl::false_ { };

#ifdef TEST_MPFR_50
template<unsigned Digits10>
struct is_mpfr_type<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::mpfr_float_backend<Digits10>>>
    : public boost::mpl::true_ { };
#endif

template<class T>
void test() {
    std::cout << "Testing type: " << typeid(T).name() << std::endl;
    static const boost::array<const char*, 51u> data = {{
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666666666666666666666666666666666667e-101",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999966666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666666666666666666668666666666666667e-97",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999999999999999999999999999996666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666686666666666666666666666666666667e-93",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999999999999999999999666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666866666666666666666666666666666666666666666666667e-89",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999999999999966666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666668666666666666666666666666666666666666666666666666666666666666667e-85",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999999999996666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666686666666666"
        "666666666666666666666666666666666666666666666666666666666666666666667e-81",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999999999999666666666666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666866666666666666666666666666"
        "666666666666666666666666666666666666666666666666666666666666666666667e-77",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999999999999966666666666666666666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666668666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666666666666666666666666666666666667e-73",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999999999996666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666686666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666666666666666666666666666666666667e-69",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999999999999666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666866666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666666666666666666666666666665238095238095238e-65",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "99999999966666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666668666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666666666666666666666666666665238095238095238095238095238095238095238e-61",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
        "96666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "66686666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"
        "666665238095238095238095238095238095238095238095238095238095238095238e-57",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999996666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666668666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666665238095238095238095"
        "238095238095238095238095238095238095238095238095238095238095238095238e-53",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666666666666666666686666666666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666665238095238095238095238095238095238095238095"
        "238095238095238095238095238095238095238095238095238096349206349206349e-49",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999966666666666666666666666"
        "66666666666666666666666666666666666666666666666666666666666666666866666666666666666666666666666666666666666666"
        "66666666666666666666666666666666666666666665238095238095238095238095238095238095238095238095238095238095238095"
        "238095238095238095238206349206349206349206349206349206349206349206349e-45",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999999999996666666666666666666666666666666"
        "66666666666666666666666666666666666666666666666668666666666666666666666666666666666666666666666666666666666666"
        "66666666666666666665238095238095238095238095238095238095238095238095238095238095238095238095238095249206349206"
        "349206349206349206349206349206349206349206349206349206349206349206349e-41",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999999999999666666666666666666666666666666666666666"
        "66666666666666666666666666666666686666666666666666666666666666666666666666666666666666666666666666666666652380"
        "95238095238095238095238095238095238095238095238095238095238095238096349206349206349206349206349206349206349206"
        "34920634920634920634920634920544011544011544011544011544011544011544e-37",
        "9."
        "99999999999999999999999999999999999999999999999999999999999999966666666666666666666666666666666666666666666666"
        "66666666666666666866666666666666666666666666666666666666666666666666666666666666652380952380952380952380952380"
        "95238095238095238095238095238095238206349206349206349206349206349206349206349206349206349206349206340115440115"
        "440115440115440115440115440115440115440115440115440116209346209346209e-33",
        "9."
        "99999999999999999999999999999999999999999999999999999996666666666666666666666666666666666666666666666666666666"
        "68666666666666666666666666666666666666666666666666666666652380952380952380952380952380952380952380952380952380"
        "95249206349206349206349206349206349206349206349206349206349115440115440115440115440115440115440115440115440115"
        "440116209346209346209346209346209346209346209346209346209346202679543e-29",
        "9."
        "99999999999999999999999999999999999999999999999666666666666666666666666666666666666666666666666866666666666666"
        "66666666666666666666666666666666652380952380952380952380952380952380952380952380963492063492063492063492063492"
        "06349206349206349205440115440115440115440115440115440115440115440116209346209346209346209346209346209346209346"
        "20934554267954267954267954267954267954267954267954268013091483679719e-25",
        "9."
        "99999999999999999999999999999999999999966666666666666666666666666666666666666668666666666666666666666666666666"
        "66666666652380952380952380952380952380952380952382063492063492063492063492063492063492063401154401154401154401"
        "15440115440115440116209346209346209346209346209346209346209279542679542679542679542679542679542679548561895620"
        "719150130914836797189738366208428128459088211410192834341441152586663e-21",
        "9."
        "99999999999999999999999999999996666666666666666666666666666666686666666666666666666666666666666523809523809523"
        "80952380952380952492063492063492063492063492063491154401154401154401154401154401162093462093462093462093462093"
        "46202679542679542679542679542679542738366208954444248561895620719149604599047323505527839893164970569113274066"
        "834438351466215243304983108499463325146458811824271509689681318218133e-17",
        "9."
        "99999999999999999999999666666666666666666666666866666666666666666666666523809523809523809523809634920634920634"
        "92063492054401154401154401154401162093462093462093462093455426795426795426795426801309148367971897383662084281"
        "28459088211410192834817631628777139613052925311641589740930163598087002528653948764327011735444703713649735994"
        "600714288656350334489593033695272837185114343249547095046272603174268e-13",
        "9."
        "99999999999999966666666666666668666666666666666523809523809523820634920634920634011544011544011620934620934620"
        "92795426795426795485618956207191496045990473235055754589407840181790511622655922027266214947464105796118350970"
        "95566286199717626418813764642659343446728207455753397291482030056516178836684094391777365260695851470017381944"
        "166954115569576329193296454393446430574957840819236721213626802085619e-9",
        "0."
        "00009999999966666666866666665238095249206349115440116209346202679542738366208428128463850116128619335776637836"
        "25356016743446481287919721529889488170726992708103099973754992548200867236379993760691596237924758432415909453"
        "64213757559975131795786106774549205128978509536127629907329130469210884560799844298882202621374002139299626915"
        "32176198436788640624698990926490105259050461938357510947570244880435664081",
        "0."
        "78539816339744830961566084581987572104929234984377645524373614807695410157155224965700870633552926699553702162"
        "83205766617734611523876455579313398520321202793625710256754846302763899111557372387325954911072027439164833615"
        "32118912058446695791317800477286412141730865087152613581662053348401815062285318431146751651578897043720380230"
        "24070731352292884109197314759000283263263720511663034603673798537790236",
        "1."
        "57069632679522995256265502498737048960652120853315174839401026935848081948102021802937891150977234063330766489"
        "41055516492022741759833189628737308869915412879148320539754700057326930986734751013960313584219296445913757777"
        "00024066556918259786849494180023619154483220638177597255994976227592745563770792563411300681783791948141133545"
        "1596526426779712759369563859151046126747697908496855825977735219514481",
        "1."
        "57079631679489661923132202497308477543189803302088624382223420091581296493675529296481107255561841855095783391"
        "04318071142673796252326115673007840833450909541260947278453938016119958041324233151995987794877839930865561434"
        "52402727021327105382917974535759059640802386727577019707570709405321600068054458025609408911380428826744908990"
        "4640326828789035666143699659867092108718279796583028512542392495421779",
        "1."
        "57079632679389661923132169163975144243191803302088624382080542948724153647643783264749360314724901018155023362"
        "17205184029120016698547471043186681600526965471042074304163483259318452680435202095109230279463923963492870040"
        "90401203274080545673814459935289342520298852460343921870792942537829537108210828162040637908281361386267215990"
        "1100496534463976107550806601465567059619048829495421806391510160463001",
        "1."
        "57079632679489651923132169163975144209858469968788624382080562948724153647643783064735074600439186732440737658"
        "99887723711659699238229101634817272120007484952330785592874771970616254211570733230640365810600043257395046296"
        "02144362023431298120608805527777397488034934747509799779662017152361144505614429670797457312684559032162361528"
        "8317089359131170138395627805178532322154433252386274406088878525130896",
        "1."
        "57079632679489661922132169163975144209858469968755291048747262948724153647643783264735074600439186730440737658"
        "99744866568802556381086244491974416088261453206299039561128740224575416159622681282588417758651991386266175167"
        "24122384001453276142520160839132708843345520828095880953977897350594283915224427582750823760478251407898080917"
        "8018719474972957865632271450490908284680846718670522639450168825443945",
        "1."
        "57079632679489661923132069163975144209858469968755291048747229615390820347643783264735074600439186732440737658"
        "99744866566802556381086244491960130373975738920584753846844454510289702985019506679413814584048816783091570881"
        "43602903481972756662000680319652189362826809630293683151780095152792086113026625318281959291536859466506139525"
        "8604800061112367475630116742454513973110064559653064241192080164878504",
        "1."
        "57079632679489661923132169153975144209858469968755291048747229615390820314310449931435074600439186732440737658"
        "99744866568802556381086244491940130373975738920584753846843025938861131556448078107985386012620245354520143421"
        "11856871735941010630254648573620332219969666682241735099832043204740138061078573370230012148756639686286359306"
        "0802602258914565277827918940256045031718123167711672299800138772937113",
        "1."
        "57079632679489661923132169163974144209858469968755291048747229615390820314310449931401741267105886732440737658"
        "99744866568802556381086244491960130373975738920584553846843025938861131556448078107985243155477388211663000563"
        "97572586021655296344540362859334729045366492079067131925228868601565423775364287655944296953951444881091554111"
        "2750654206966513329776061797398902251498342947931452519580358553156893",
        "1."
        "57079632679489661923132169163975144109858469968755291048747229615390820314310449931401741267105853399107404358"
        "99744866568802556381086244491960130373975738920584753846843025938861129556448078107985243155477388211663000563"
        "97571157450226724915968934287906300473937920650495703353800297172994106315046827338483979493633984563631125539"
        "8464939921252227615490256602593707446303537753126257714385553358352607",
        "1."
        "57079632679489661923132169163975144209848469968755291048747229615390820314310449931401741267105853399107404325"
        "66411533238802556381086244491960130373975738920584753846843025938861131556448078107985243135477388211663000563"
        "97571157450226724915968934287906157616795063507638560496657454315851249172189684481341122350776841706488379508"
        "1004622460934767298029939142275136017732109181697686285814124786923127",
        "1."
        "57079632679489661923132169163975144209858468968755291048747229615390820314310449931401741267105853399107404325"
        "66411533235469223047756244491960130373975738920584753846843025938861131556448078107985243155477388211663000563"
        "77571157450226724915968934287906157616795063507638560496657440030136963457903970195626838065062555992202665222"
        "3861765318077624440887081999419104271700363149951654539782378755175984",
        "1."
        "57079632679489661923132169163975144209858469968655291048747229615390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626800373975738920584753846843025938861131556448078107985243155477388211663000563"
        "97571157450226724915768934287906157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "8147481032363338726601367713704818557414648864237368825496664469462809",
        "1."
        "57079632679489661923132169163975144209858469968755281048747229615390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405590584753846843025938861131556448078107985243155477388211663000563"
        "97571157450226724915968934287906157616793063507638560496657440030136963457903970195626836636491127420774093793"
        "8147479603791910155172796285133390128843220292808797396925235898034238",
        "1."
        "57079632679489661923132169163975144209858469968755291047747229615390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513513025938861131556448078107985243155477388211663000563"
        "97571157450226724915968934287906157616795063507638560496657420030136963457903970195626836636491127420774093793"
        "8147479603791910155172796285133389985986077435665940254068093055177095",
        "1."
        "57079632679489661923132169163975144209858469968755291048747129615390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527801556448078107985243155477388211663000563"
        "97571157450226724915968934287906157616795063507638560496657440030136963457903969995626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229605390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744777985243155477388211663000563"
        "97571157450226724915968934287906157616795063507638560496657440030136963457903970195626836636491127418774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615389820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822147388211663000563"
        "97571157450226724915968934287906157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "814747960359191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820214310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329670563"
        "97571157450226724915968934287906157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513138998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314300449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824450226724915968934287906157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566592025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310448931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582968934287906157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931301741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582635600954573157616795063507638560496657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931401731267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582635600954572824283461730507638560496657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741266105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582635600954572824283461730174305227163657440030136963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105753399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582635600954572824283461730174305227163324106696803963457903970195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853389107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "64237824116893391582635600954572824283461730174305227163324106696803630124570637195626836636491127420774093793"
        "814747960379191015517279628513338998598607743566594025406809304089138",
    }};

    T arg = static_cast<T>("1e-100");

    unsigned max_err = 0;
    for (unsigned k = 0; k < data.size(); k++) {
        T val = atan(arg);
        T e = relative_error(val, T(data[k]));
        unsigned err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
        val = atan(-arg);
        e = relative_error(val, T(-T(data[k])));
        err = e.template convert_to<unsigned>();
        if (err > max_err) {
            max_err = err;
        }
        arg *= 10000;
    }
    std::cout << "Max error was: " << max_err << std::endl;
    BOOST_TEST(max_err < 10);
    BOOST_TEST(atan(T(0)) == 0);

    //
    // And again, but test all the phases of atan2:
    //
    arg = static_cast<T>("1e-100");
    unsigned err;
    for (unsigned k = 0; k < data.size(); k++) {
        T val = atan2(arg, 1);
        T e = relative_error(val, atan2_def(arg, T(1)));
        err = e.template convert_to<unsigned>();
        if (err > max_err) {
            max_err = err;
        }
        val = atan2(-arg, 1);
        e = relative_error(val, atan2_def(T(-arg), T(1)));
        err = e.template convert_to<unsigned>();
        if (err > max_err) {
            max_err = err;
        }
        val = atan2(arg, -1);
        e = relative_error(val, atan2_def(arg, T(-1)));
        err = e.template convert_to<unsigned>();
        if (err > max_err) {
            max_err = err;
        }
        val = atan2(-arg, -1);
        e = relative_error(val, atan2_def(T(-arg), T(-1)));
        err = e.template convert_to<unsigned>();
        if (err > max_err) {
            max_err = err;
        }
        arg *= 10000;
    }
    //
    // special cases:
    //
    err = relative_error(T(atan2(T(0), T(1))), atan2_def(T(0), T(1))).template convert_to<unsigned>();
    if (err > max_err)
        max_err = err;
    if (!nil::crypto3::multiprecision::is_interval_number<T>::value) {
        // We don't test this with intervals as [-0,0] leads to strange behaviour in atan2...
        err = relative_error(T(atan2(T(0), T(-1))), atan2_def(T(0), T(-1))).template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }

    T pi;
    pi.backend() = nil::crypto3::multiprecision::default_ops::get_constant_pi<typename T::backend_type>();

    err = relative_error(T(atan2(T(1), T(0))), T(pi / 2)).template convert_to<unsigned>();
    if (err > max_err)
        max_err = err;

    err = relative_error(T(atan2(T(-1), T(0))), T(pi / -2)).template convert_to<unsigned>();
    if (err > max_err)
        max_err = err;

    T mv = (std::numeric_limits<T>::max)();
    err = relative_error(T(atan2(mv, T(1))), T(pi / 2)).template convert_to<unsigned>();
    if (err > max_err)
        max_err = err;
    err = relative_error(T(atan2(-mv, T(1))), T(pi / -2)).template convert_to<unsigned>();
    if (err > max_err)
        max_err = err;

    if (std::numeric_limits<T>::has_infinity) {
        mv = (std::numeric_limits<T>::infinity)();
        err = relative_error(T(atan2(mv, T(1))), T(pi / 2)).template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
        err = relative_error(T(atan2(-mv, T(1))), T(pi / -2)).template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }

    std::cout << "Max error was: " << max_err << std::endl;
    BOOST_TEST(max_err < 2000);
}

int main() {
#ifdef TEST_BACKEND
    test<
        nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::concepts::number_backend_float_architype>>();
#endif
#ifdef TEST_MPF_50
    test<nil::crypto3::multiprecision::mpf_float_50>();
    test<nil::crypto3::multiprecision::mpf_float_100>();
#endif
#ifdef TEST_MPFR_50
    test<nil::crypto3::multiprecision::mpfr_float_50>();
    test<nil::crypto3::multiprecision::mpfr_float_100>();
#endif
#ifdef TEST_MPFI_50
    test<nil::crypto3::multiprecision::mpfi_float_50>();
    test<nil::crypto3::multiprecision::mpfi_float_100>();
#endif
#ifdef TEST_CPP_DEC_FLOAT
    test<nil::crypto3::multiprecision::cpp_dec_float_50>();
    test<nil::crypto3::multiprecision::cpp_dec_float_100>();
#ifndef SLOW_COMPLER
    // Some "peculiar" digit counts which stress our code:
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<65>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<64>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<63>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<62>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<61, long long>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<60, long long>>>();
    test<nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::cpp_dec_float<59, long long, std::allocator<char>>>>();
    test<nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::cpp_dec_float<58, long long, std::allocator<char>>>>();
    // Check low multiprecision digit counts.
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<9>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<18>>>();
#endif
#endif
#ifdef TEST_FLOAT128
    test<nil::crypto3::multiprecision::float128>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
    test<nil::crypto3::multiprecision::cpp_bin_float_50>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_bin_float<
        35, nil::crypto3::multiprecision::digit_base_10, std::allocator<char>, boost::long_long_type>>>();
#endif
    return boost::report_errors();
}
